// Package
// @author: byz08
// @description:
// @file: user
// @version: 1.0.0
// @date: 2022/6/8 9:25
package main

import (
	"fmt"
	"net"
	"strings"
)

type User struct {
	Name    string
	Addr    string
	Channel chan string
	conn    net.Conn
	server  *Server
}

func NewUser(conn net.Conn, server *Server) *User {
	user := &User{
		Name:    "user_" + conn.RemoteAddr().String(),
		Addr:    conn.RemoteAddr().String(),
		Channel: make(chan string),
		conn:    conn,
		server:  server,
	}
	//启动监听消息
	go user.ListenMessage()
	return user
}

// ListenMessage
// @Description: 监听channel go程，有消息就会发送给客户端
// @receiver this
func (this *User) ListenMessage() {
	for {
		//使用range读取channel当channel关闭之后range会自动跳出循环，不会执行write操做
		for msg := range this.Channel {
			_, err := this.conn.Write([]byte(msg + "\n"))
			if err != nil {
				fmt.Println("send msg has error：", err)
				continue
			}
		}
		//这里，关闭的socket上执行read操作会得到EOF error，但write操作会成功，因为数据会成功写入己方的内核socket缓冲区中
		//但是会抛出use of closed network connection，因此这里使用range规避了这个问题
		//msg := <-this.Channel
		//fmt.Println("userChannel:" + msg)
		//_, err := this.conn.Write([]byte(msg + "\n"))
		//if err != nil {
		//	fmt.Println("send msg has error：", err)
		//	continue
		//}
	}
}

// Online
// @Description: 用户上线业务
// @receiver this
func (this *User) Online() {
	//1.用户加入onlineMap中
	this.server.mapLock.Lock()
	this.server.OnlineMap[this.Name] = this
	this.server.mapLock.Unlock()
	//2.广播用户上线
	this.server.BroadCastToUSer(this, "successful online!")
}

// OffLine
// @Description: 用户下线
// @receiver this
func (this *User) OffLine() {
	//用户下线
	this.server.mapLock.Lock()
	delete(this.server.OnlineMap, this.Name)
	this.server.BroadCastToUSer(this, "offline!")
	fmt.Println("user " + this.Name + " offline")
	this.server.mapLock.Unlock()
}

// SendMsgToThisUser
// @Description: 发送一条消息给用户
// @receiver this
// @param msg
func (this *User) SendMsgToThisUser(msg string) {
	_, err := this.conn.Write([]byte(msg + "\n"))
	if err != nil {
		fmt.Println("user has error：", err)
	}
}

// DoMessage
// @Description: 发送消息给用户
// @receiver this
// @param msg
func (this *User) DoMessage(msg string) {
	if msg == "who" {
		//查询当前用户有哪些
		this.server.mapLock.Lock()
		for _, user := range this.server.OnlineMap {
			onlineMsg := "--" + "." + user.Name + ":online"
			//发送给当前对象
			this.SendMsgToThisUser(onlineMsg)
		}
		this.server.mapLock.Unlock()
	} else if len(msg) > 7 && msg[:7] == "rename|" {
		newName := strings.Split(msg, "|")[1]
		_, ok := this.server.OnlineMap[newName]
		if !ok {
			delete(this.server.OnlineMap, this.Name)
			this.server.OnlineMap[newName] = this
			this.Name = newName
			msg := "[system]: edit userName success , your new Name is " + newName
			this.SendMsgToThisUser(msg)
			return
		}
		msg := "[system]: your name want to set had been set by others , please reset!"
		this.SendMsgToThisUser(msg)
	} else if len(msg) > 4 && msg[:3] == "to|" {
		//规定协议to|张三|内容
		msgSlice := strings.Split(msg, "|")
		if msgSlice[1] == "" {
			this.SendMsgToThisUser("[system]: send to someone failure please check your input format , please input like \"to|user|msg\"")
			return
		}
		if msgSlice[2] == "" {
			this.SendMsgToThisUser("[system]: please input dont allow input empty msg to someone , please input like \"to|user|msg\"")
			return
		}
		//1.根据用户名获取用户对象
		toUser, ok := this.server.OnlineMap[msgSlice[1]]
		//用户不存在
		if !ok {
			this.SendMsgToThisUser("[system]: user dont exist !")
			return
		}
		//2.发送消息内容给目标用户
		toUser.SendMsgToThisUser("@[" + this.Addr + "]" + this.Name + ": " + msgSlice[2])
		//3.标记消息已送达
		this.SendMsgToThisUser("[system]: your message has successfully sent")
	} else {
		//正常发送消息
		//fmt.Println("send msg ing")
		this.server.BroadCastToUSer(this, msg)
	}
}
